package cn.liumouren.tool.security.autoconfigure.util;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;

/**
 * 反射工具类
 *
 * @author Daniel Liu
 * @date 2021/3/9 20:42
 */
public class ReflectUtil {

    /**
     * 获取obj的指定属性值
     *
     * @param clazz obj所属Class
     * @param o     obj
     * @param field 属性值
     * @param <T>   返回类型
     * @return obj的指定属性值
     */
    @SuppressWarnings("unchecked")
    public static <T> T getField(Class<?> clazz, Object o, String field) {
        T t = null;
        try {
            Field f = clazz.getDeclaredField(field);
            f.setAccessible(true);
            t = (T) f.get(o);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return t;
    }

    /**
     * 执行obj指定方法
     *
     * @param clazz      obj所在Class
     * @param o          obj
     * @param methodName 方法名
     * @param argsClass  参数类型集合
     * @param args       参数
     * @param <T>        需要返回的类型
     * @return 执行结果
     */
    @SuppressWarnings("unchecked")
    public static <T> T invoke(Class<?> clazz, Object o, String methodName, Collection<Class<?>> argsClass, Collection<Object> args) {
        Object res = null;
        try {
            Method method = clazz.getDeclaredMethod(methodName, argsClass.toArray(new Class[0]));
            method.setAccessible(true);
            res = method.invoke(o, args.toArray(new Object[0]));
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
        return (T) res;
    }

    /**
     * 执行obj指定无参方法
     *
     * @param clazz      obj所在Clazz
     * @param o          obj
     * @param methodName 方法名
     * @param <T>        返回类型
     * @return 执行结果
     */
    @SuppressWarnings("unchecked")
    public static <T> T invoke(Class<?> clazz, Object o, String methodName) {
        Object res = null;
        try {
            Method method = clazz.getDeclaredMethod(methodName);
            method.setAccessible(true);
            res = method.invoke(o);
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
        return (T) res;
    }

    /**
     * 获取指定类的方法
     *
     * @param clazz       目标Class
     * @param methodName  方法名
     * @param argsClasses 参数Classes
     * @return 指定方法
     */
    public static Method getMethod(Class<?> clazz, String methodName, Class<?>... argsClasses) {
        Method res = null;
        try {
            if (argsClasses == null) {
                res = clazz.getDeclaredMethod(methodName);
            } else {
                res = clazz.getDeclaredMethod(methodName, argsClasses);
            }
            res.setAccessible(true);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return res;
    }

    /**
     * 获取指定类的无参方法
     *
     * @param clazz      目标Class
     * @param methodName 方法名
     * @return 指定方法
     */
    public static Method getMethod(Class<?> clazz, String methodName) {
        return getMethod(clazz, methodName, (Class<?>) null);
    }

    /**
     * 执行obj的目标方法
     *
     * @param method 方法
     * @param o      obj
     * @param args   参数
     * @param <T>    返回类型
     * @return 执行结果
     */
    @SuppressWarnings("unchecked")
    public static <T> T invoke(Method method, Object o, Object... args) {
        Object res = null;
        try {
            res = args == null ? method.invoke(o) : method.invoke(o, args);
        } catch (IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
        return (T) res;
    }


    /**
     * 执行obj的目标方法
     *
     * @param method 方法
     * @param o      obj
     * @param <T>    返回类型
     * @return 执行结果
     */
    public static <T> T invoke(Method method, Object o) {
        return invoke(method, o, (Object) null);
    }

}
